﻿using System;
using System.Text;
using System.IO.Ports;
using System.Collections;
using System.Threading;

namespace JN.Utility
{
    public class SyncSerialPort : IDisposable
    {
        private SerialPort _serialPort;
        private AutoResetEvent _processMessage = new AutoResetEvent(false);
        private Thread _processThread = null;
        private Queue _queue = new Queue(10000);
        private bool _disposing = false;

        public SerialPort SerialPort
        {
            get { return _serialPort; }
        }

        public SyncSerialPort(SerialPort serialPort)
        {
            if (_serialPort != null)
            {
                _serialPort.Close();
                _serialPort.Dispose();
            }
            _serialPort = serialPort;
        }

        public void Start()
        {
            if (_serialPort == null)
            {
                throw new Exception("SerialPort object is null!");
            }

            try
            {
                _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
                _serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(_serialPort_ErrorReceived);
                _serialPort.Open();

                _processThread = new Thread(new ThreadStart(TakeOutData));
                _processThread.IsBackground = true;
                _processThread.Start();
                _processMessage.Set();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        void _serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
        }

        public void SendData(byte[] data)
        {
            try
            {
                if (_serialPort.IsOpen)
                    _serialPort.Write(data, 0, data.Length);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void SendData(string data)
        {
            SendData(Encoding.ASCII.GetBytes(data));
        }

        public void SendData(char[] data)
        {
            try
            {
                if (_serialPort.IsOpen)
                    _serialPort.Write(data, 0, data.Length);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        // 数据接收事件,由SerialPort组件产生
        private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (e.EventType != SerialData.Chars)
            {
                return;
            }

            if (_serialPort.BytesToRead <= 0)
            {
                return;
            }

            byte[] readBuffer = new byte[_serialPort.BytesToRead];
            _serialPort.Read(readBuffer, 0, readBuffer.Length);
            _queue.Enqueue(readBuffer);

            _processMessage.Set();
        }

        private void TakeOutData()
        {
            do
            {
                while (_queue.Count > 0)
                {
                    byte[] data = (byte[])_queue.Dequeue();

                    if (BytesReceived != null)
                    {
                        BytesReceived(this, new BytesReceivedEventArgs(data));
                    }
                    if (StringReceived != null)
                    {
                        StringReceived(this, new StringReceivedEventArgs(Encoding.ASCII.GetString(data)));
                    }
                }

                _processMessage.WaitOne();
            } while (!_disposing);
        }

        public event EventHandler<StringReceivedEventArgs> StringReceived;
        public event EventHandler<BytesReceivedEventArgs> BytesReceived;

        ~SyncSerialPort()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                //清理托管的对象
                _serialPort.Close();
                _serialPort.Dispose();

                _disposing = true;
                _processMessage.Set();
                _processMessage.Close();
            }
        }

        #region IDisposable 成员

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        #endregion
    }

    public class StringReceivedEventArgs : EventArgs
    {
        private string _data;

        public string Data
        {
            get
            {
                return _data;
            }
        }

        public StringReceivedEventArgs(string data)
        {
            _data = data;
        }
    }

    public class BytesReceivedEventArgs : EventArgs
    {
        private byte[] _data;

        public byte[] Data
        {
            get
            {
                return _data;
            }
        }

        public BytesReceivedEventArgs(byte[] data)
        {
            _data = data;
        }
    }

}
